using System;
using System.IO;
using System.Windows;
using Autofac;
using log4net;
using log4net.Config;
using YZAutoDWR.Data;
using YZAutoDWR.Handler;
using static System.IO.Path;

namespace YZAutoDWR;

/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App
{
    private static IContainer? _container;
    private ILifetimeScope? _appScope;
    public static ConfigHandler? ConfigHandler { get; set; }

    private static readonly ILog Log = LogManager.GetLogger(typeof(App));

    /** 依赖注入配置 */
    private static void ConfigureContainer(ContainerBuilder builder)
    {
        builder.RegisterType<DWRDbContext>().AsSelf().InstancePerDependency();
        builder.RegisterType<AutoMigrationService>().AsSelf().SingleInstance();
        builder.RegisterType<ServiceTableInitializer>().AsSelf().SingleInstance();
        builder.RegisterType<ConfigHandler>().AsSelf().SingleInstance();
        builder.RegisterType<ContextMenuHandler>().AsSelf().SingleInstance();
        builder.RegisterType<WeWorkHandler>().AsSelf().InstancePerDependency();
    }

    protected override void OnStartup(StartupEventArgs e)
    {
        base.OnStartup(e);

        ConfigLog4Net();

        var builder = new ContainerBuilder();
        ConfigureContainer(builder);
        _container = builder.Build();

        ConfigMigration();

        _container.Resolve<ServiceTableInitializer>().InitializeServiceTable();
        _container.Resolve<ContextMenuHandler>().InitializeContextMenu();
        _appScope = _container.BeginLifetimeScope();
        ConfigHandler = _appScope.Resolve<ConfigHandler>();
    }

    /** 配置 Log4Net */
    private static void ConfigLog4Net()
    {
        var logDirectory = Combine(AppDomain.CurrentDomain.BaseDirectory, "logs");
        if (!Directory.Exists(logDirectory))
        {
            Directory.CreateDirectory(logDirectory);
        }

        var logFilePath = Combine(AppDomain.CurrentDomain.BaseDirectory, "logs\\AppLog.log");
        GlobalContext.Properties["LogFileName"] = logFilePath;
        XmlConfigurator.Configure(new FileInfo("Log4Net.config"));

        Log.Info("Log4Net 已被初始化 -- 这是一条测试日志...");

        var configFile = new FileInfo("Log4Net.config");
        if (configFile.Exists)
        {
            XmlConfigurator.Configure(configFile);
            Log.Info("Log4Net 配置文件已加载");
        }
        else
        {
            Console.WriteLine("未找到 Log4Net 配置文件");
        }

        Log.Info("当前日志文件路径为: " + Combine(logDirectory, "AppLog.log"));
    }

    /// <summary>
    /// 从依赖注入容器中获取指定类型的实例
    /// </summary>
    /// <typeparam name="T">已经进行依赖注入管理的类型</typeparam>
    /// <returns>指定类型的依赖注入实例</returns>
    public static T Resolve<T>() where T : notnull
    {
        if (_container == null) throw new InvalidOperationException("依赖注入容器未初始化");
        try
        {
            return _container.Resolve<T>();
        }
        catch (Autofac.Core.Registration.ComponentNotRegisteredException ex)
        {
            Log.Error($"类型 {typeof(T).Name} 未在依赖注入容器中注册, 无法获取对应的实例:" + ex);
            throw new InvalidOperationException($"类型 {typeof(T).Name} 未在依赖注入容器中注册", ex);
        }
        catch (Autofac.Core.DependencyResolutionException ex)
        {
            Log.Error($"解析类型 {typeof(T).Name} 时发生依赖解析错误:" + ex);
            throw new InvalidOperationException($"解析 {typeof(T).Name} 时出错", ex);
        }
    }

    /** 表结构发生变动时执行数据库迁移 */
    private void ConfigMigration()
    {
        try
        {
            _container?.Resolve<AutoMigrationService>().RunAutoMigration();
        }
        catch (Exception e)
        {
            Log.Fatal("数据库迁移失败" + e);
            MessageBox.Show("致命错误: 数据库迁移时发生了异常", "数据库迁移异常", MessageBoxButton.OK, MessageBoxImage.Error);
            Shutdown();
        }
    }

    protected override void OnExit(ExitEventArgs e)
    {
        ConfigHandler?.Dispose();
        _appScope?.Dispose();
        _container?.Dispose();
        base.OnExit(e);
    }
}